﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using Core.Models;
using DotNetOpenAuth.OpenId.RelyingParty;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
using OliveLite.Core.Membership;

namespace Core.Controllers
{
    public class AccountController : Controller
    {

        public IFormsAuthenticationService FormsService { get; set; }
        public IMembershipService MembershipService { get; set; }
        static private OpenIdRelyingParty openid = new OpenIdRelyingParty();

        protected override void Initialize(RequestContext requestContext)
        {
            if (FormsService == null) { FormsService = new FormsAuthenticationService(); }
            if (MembershipService == null) { MembershipService = new AccountMembershipService(); }

            base.Initialize(requestContext);
        }

        //
        // POST: /Account/Create

        [HttpPost]
        public ActionResult Create(UserUI user)
        {
            if(user.BusinessUnitId.Equals(Guid.Empty))
            {
                ModelState.Clear();
                user.UserId = Guid.Empty;
                user.BusinessUnitId = (Guid)Session["BusinessUnitId"];
                ViewBag.CreateMessage = "";
                return View(user);
            }
            if (!ModelState.IsValid)
            {
                ViewBag.CreateMessage = "";
                return View(user);
            }
            CoreEntities core = new CoreEntities();
            List<ContactUser> cus = core.ContactUsers.Where(m => m.Contact.Email == user.Email).ToList();
            // Check if Contact is a user in the system
            if (cus.Count() > 0)
            {
                //Contact is a user, so check if contact is associated to BU
                ContactUser cu = cus[0];
                List<User> users = core.Users.Where(m => (m.ContactId == cu.ContactId && m.BusinessUnitId == user.BusinessUnitId)).ToList();
                if (users.Count() > 0)
                {
                    if (cu.InviteExpires < DateTime.Now && cu.IsApprovedYN == "N")
                    {
                        cu.InviteCode = Tools.RandomString(10, false);
                        cu.InviteExpires = DateTime.Now.AddHours(6);
                        core.SaveChanges();
                        Contact c = cu.Contact;
                        BusinessUnit bu = core.BusinessUnits.First(m => m.BusinessUnitId == user.BusinessUnitId);
                        string emailbody = "Welcome! " +
                            "You are invited to create an account for " + bu.BusinessUnitName + ".<br /><br />" +
                            "To create the account please visit http://" + Session["DomainName"].ToString() + "/Account/Register <br /><br />" +
                            "You will need the email address where you received this notification and a security code. Your security code is:<br /><br />" +
                            cu.InviteCode + "<br /><br />" +
                            "Please note that for security purposes the above code will expire in approximately 6 hrs.<br /><br />" +
                            "If you think you have received this in error, please ignore this email<br />Thank you.";
                        string subject = "Account creation for " + bu.BusinessUnitName;
                        List<EmailAddress> to = new List<EmailAddress>();
                        to.Add(new EmailAddress((c.FirstName + (String.IsNullOrEmpty(c.LastName) ? "" : " " + c.LastName)), c.Email));
                        Core.Tools.SendMail((Guid)Session["DomainId"], subject, emailbody, to);
                        ViewBag.CreateMessage = "An invitation has been sent to your specified email address with further instructions.";
                    }
                    else
                    {
                        ModelState.AddModelError("", "You are already registered. If you have issues logging on, please contact the system administrator.");
                        ModelState.AddModelError("", "If you have just created an account, you probably need to check your email to complete the registration process.");
                        ViewBag.CreateMessage = "";
                    }
                    return View(user);
                }
                else
                {
                    User u = CreateUser(user, ref core, cu);
                    AuthorizeUserForClientRole(ref core, u);
                    core.SaveChanges();
                    ViewBag.CreateMessage = "Associated to Business Unit! Please Log On";
                    return View(user);
                }
            }
            else
            {
                // Contact is not a user so go ahead and Invite
                List<Contact> contacts = core.Contacts.Where(m => m.Email == user.Email).ToList();
                Contact c;
                if (contacts.Count() <= 0)
                {
                    c = new Contact();
                    c.ContactId = Guid.NewGuid();
                    c.FirstName = user.FirstName;
                    c.LastName = user.LastName;
                    c.Email = user.Email;
                    c.Status = "C";
                    c.EmailVerifiedYN = "N";
                    c.IsDroppedYN = "N";
                    c.CreatedDT = DateTime.Now;
                    c.CreatedById = c.ContactId;
                    c.CreatedByName = "Self Registered";
                    c.ModifiedDT = DateTime.Now;
                    c.ModifiedById = c.ContactId;
                    c.ModifiedByName = "Self Registered";
                    core.AddToContacts(c);
                }
                else
                {
                    c = contacts[0];
                }
                ContactUser cu = new ContactUser();
                cu.ContactId = c.ContactId;
                cu.OpenIDUserName = c.Email;
                cu.Password = Core.Tools.RandomString(10, false);
                cu.InviteCode = Core.Tools.RandomString(10, false);
                cu.InviteExpires = DateTime.Now.AddHours(6);
                cu.IsDroppedYN = "N";
                cu.IsApprovedYN = "N";
                cu.IsLockedOutYN = "Y";
                cu.IsOnLineYN = "N";
                cu.CreateDT = DateTime.Now;
                cu.FailedPasswordAttemptCount = 0;
                cu.FailedPasswordAnswerAttemptCount = 0;
                core.AddToContactUsers(cu);
                User u = CreateUser(user, ref core, cu);
                AuthorizeUserForClientRole(ref core, u);
                core.SaveChanges();
                BusinessUnit bu = core.BusinessUnits.First(m => m.BusinessUnitId == user.BusinessUnitId);
                string emailbody = "Welcome! " +
                    "You are invited to create an account for " + bu.BusinessUnitName + ".<br /><br />" +
                    "To create the account please visit http://" + Session["DomainName"].ToString() + "/Account/Register <br /><br />" +
                    "You will need the email address where you received this notification and a security code. Your security code is:<br /><br />" +
                    cu.InviteCode + "<br /><br />" +
                    "Please note that for security purposes the above code will expire in approximately 6 hrs.<br /><br />" +
                    "If you think you have received this in error, please ignore this email<br />Thank you.";
                string subject = "Account creation for " + bu.BusinessUnitName;
                List<EmailAddress> to = new List<EmailAddress>();
                to.Add(new EmailAddress((c.FirstName + (String.IsNullOrEmpty(c.LastName) ? "" : " " + c.LastName)), c.Email));
                Core.Tools.SendMail((Guid)Session["DomainId"], subject, emailbody, to);
                ViewBag.CreateMessage = "An invitation has been sent to your specified email address with further instructions.";
                return View(user);
            }
        }

        private static void AuthorizeUserForClientRole(ref CoreEntities core, User u)
        {
            Guid ClientRole = core.Roles.First(m => m.Name == "Client User").RoleId;
            Authorization auth = new Authorization();
            auth.AuthorizationId = Guid.NewGuid();
            auth.UserId = u.UserId;
            auth.RoleId = ClientRole;
            auth.IsDroppedYN = "N";
            auth.CreateDT = DateTime.Now;
            auth.CreatedById = auth.UserId;
            auth.CreatedByName = "Self Authorized";
            auth.ModifiedDT = DateTime.Now;
            auth.ModifiedById = auth.UserId;
            auth.ModifiedByName = "Self Authorized";
            core.AddToAuthorizations(auth);
        }

        private User CreateUser(UserUI user, ref CoreEntities core, ContactUser cu)
        {
            User u = new User();
            u.UserId = Guid.NewGuid();
            u.ContactId = cu.ContactId;
            u.BusinessUnitId = user.BusinessUnitId;
            u.IsDroppedYN = "N";
            u.CreateDT = DateTime.Now;
            u.CreatedById = u.UserId;
            u.CreatedByName = "Self Registered";
            u.ModifiedDT = DateTime.Now;
            u.ModifiedById = u.UserId;
            u.ModifiedByName = "Self Registered";
            core.AddToUsers(u);
            return u;
        }

        // **************************************
        // URL: /Account/LogOn
        // **************************************

        public ActionResult LogOn()
        {
            // Process OpenID Auth response for providers using GET & not POST especially Google
            var response = openid.GetResponse();
            if (response != null)
            {
                // Stage 3: OpenID Provider sending assertion response
                string returnUrl = Session["ReturnUrl"].ToString();
                LogOnModel model = (LogOnModel)Session["LogonModel"];
                switch (response.Status)
                {
                    case AuthenticationStatus.Authenticated:
                        MembershipUser user = Membership.GetUser(response.ClaimedIdentifier, true);
                        if (user != null)
                        {
                            CoreEntities core = new CoreEntities();
                            Guid mId = new Guid(user.ProviderUserKey.ToString());
                            List<User> ulist = core.Users.Where(m => (m.ContactId == mId && m.IsDroppedYN == "N")).ToList();
                            bool fnd = true;
                            if (ulist.Count > 1) /* The user clearly has access to multiple BUs so redirect to select BU */
                            {
                                Guid ContactId = ulist[0].ContactId;
                                Session["ReturnUrl"] = returnUrl;
                                Session["RememberMe"] = model.RememberMe;
                                Session["UserContactId"] = ulist[0].ContactId;
                                return RedirectToAction("BusinessUnit", new { id = ContactId });
                            }
                            else if (ulist.Count < 1) /* The user obviously does not have access as there is no user record */
                            {
                                fnd = false;
                            }
                            else if (ulist.Count == 1) /* Allow user to select a BU for Sys Admins & Domain Admins by passing ContactId as Guid empty */
                            {
                                Guid UserId = ulist[0].UserId;
                                List<Authorization> auth = core.Roles.First(m => m.Name == "System Administrator").Authorizations.Where(u => u.UserId == UserId).ToList();
                                if (auth.Count > 0)
                                {
                                    Guid ContactId = Guid.Empty;
                                    Session["ReturnUrl"] = returnUrl;
                                    Session["RememberMe"] = model.RememberMe;
                                    Session["UserContactId"] = ulist[0].ContactId;
                                    return RedirectToAction("BusinessUnit", new { id = ContactId });
                                }
                                auth = core.Roles.First(m => m.Name == "Domain Administrator").Authorizations.Where(u => u.UserId == UserId).ToList();
                                if (auth.Count > 0)
                                {
                                    Guid ContactId = Guid.Empty;
                                    Session["ReturnUrl"] = returnUrl;
                                    Session["RememberMe"] = model.RememberMe;
                                    Session["UserContactId"] = ulist[0].ContactId;
                                    return RedirectToAction("BusinessUnit", new { id = ContactId });
                                }
                            }
                            if (fnd)
                            {
                                Guid UserId = ulist[0].UserId;
                                Contact C = core.Contacts.First(m => m.ContactId == ulist[0].ContactId);
                                Session["UserId"] = UserId;
                                Session["UserFullName"] = C.FullName;
                                Session["UserEmail"] = C.Email;
                                Session["BusinessUnitId"] = ulist[0].BusinessUnitId;
                                Session["BusinessUnitName"] = ulist[0].BusinessUnit.BusinessUnitName;
                                FormsService.SignIn(UserId.ToString(), model.RememberMe);
                                if (Url.IsLocalUrl(returnUrl))
                                {
                                    return Redirect(returnUrl);
                                }
                                else
                                {
                                    return RedirectToAction("Index", "Home");
                                }
                            }
                            else
                                ModelState.AddModelError("", "Not authorized in this Business Unit.");
                        }
                        else
                        {
                            ModelState.AddModelError("", "Account for that login was not found.");
                            return View(model);
                        }
                        return View(model);
                    case AuthenticationStatus.Canceled:
                        ModelState.AddModelError("", "Canceled at provider");
                        return View(model);
                    case AuthenticationStatus.Failed:
                        ModelState.AddModelError("", response.Exception.Message);
                        return View(model);
                }
            }
            return View();
        }

        [HttpPost]
        public ActionResult LogOn(LogOnModel model, string returnUrl)
        {
            var response = openid.GetResponse();
            if (response == null)
            {
                if (ModelState.IsValid)
                {
                    // Check to make sure that user has provided either an OpenId or Email for authentication
                    if (String.IsNullOrEmpty(model.openid_identifier) && String.IsNullOrEmpty(model.Email))
                    {
                        ModelState.AddModelError("", "You have to use OpenID or Member account to LogOn.");
                        return View(model);
                    }

                    // If user has provided OpenId, setup the request object for OpenId authentication and redirect
                    // The response will be processed in the else branch of the main If statement
                    if (!String.IsNullOrEmpty(model.openid_identifier))
                    {
                        try
                        {
                            var request = openid.CreateRequest(model.openid_identifier);
                            request.AddExtension(new ClaimsRequest
                            {
                                FullName = DemandLevel.Require,
                                Email = DemandLevel.Require,
                                Nickname = DemandLevel.Require,
                                Country = DemandLevel.Request,
                                PostalCode = DemandLevel.Request,
                                TimeZone = DemandLevel.Request
                            });
                            Session["ReturnUrl"] = returnUrl;
                            Session["LogonModel"] = model;
                            return request.RedirectingResponse.AsActionResult();
                        }
                        catch (ProtocolException ex)
                        {
                            ModelState.AddModelError("", ex.Message);
                            return View(model);
                        }
                    }

                    // If the user provided an Email address, authenticate using the password provided.
                    if (MembershipService.ValidateUser(model.Email, model.Password))
                    {
                        CoreEntities core = new CoreEntities();
                        List<User> ulist = core.Users.Where(m => (m.Contact.Email == model.Email && m.IsDroppedYN == "N")).ToList();
                        bool fnd = true;
                        if (ulist.Count > 1) /* The user clearly has access to multiple BUs so redirect to select BU */
                        {
                            Guid ContactId = ulist[0].ContactId;
                            Session["ReturnUrl"] = returnUrl;
                            Session["RememberMe"] = model.RememberMe;
                            Session["UserContactId"] = ulist[0].ContactId;
                            return RedirectToAction("BusinessUnit", new { id = ContactId });
                        }
                        else if(ulist.Count < 1) /* The user obviously does not have access as there is no user record */
                        {
                            fnd = false;
                        }
                        else if (ulist.Count == 1) /* Allow user to select a BU for Sys Admins & Domain Admins by passing ContactId as Guid empty */
                        {
                            Guid UserId = ulist[0].UserId;
                            List<Authorization> auth = core.Roles.First(m => m.Name == "System Administrator").Authorizations.Where(u => u.UserId == UserId).ToList();
                            if (auth.Count > 0)
                            {
                                Guid ContactId = Guid.Empty;
                                Session["ReturnUrl"] = returnUrl;
                                Session["RememberMe"] = model.RememberMe;
                                Session["UserContactId"] = ulist[0].ContactId;
                                return RedirectToAction("BusinessUnit", new { id = ContactId });
                            }

                            auth = core.Roles.First(m => m.Name == "Domain Administrator").Authorizations.Where(u => u.UserId == UserId).ToList();
                            if (auth.Count > 0)
                            {
                                Guid ContactId = Guid.Empty;
                                Session["ReturnUrl"] = returnUrl;
                                Session["RememberMe"] = model.RememberMe;
                                Session["UserContactId"] = ulist[0].ContactId;
                                return RedirectToAction("BusinessUnit", new { id = ContactId });
                            }
                        }
                        // User is not an admin and does not have access to multiple BUs
                        if (fnd)
                        {
                            Guid UserId = ulist[0].UserId;
                            Guid ContactId = ulist[0].ContactId;
                            Contact C = core.Contacts.First(m => m.ContactId == ContactId);
                            Session["UserId"] = UserId;
                            Session["UserFullName"] = C.FullName;
                            Session["UserEmail"] = C.Email;
                            Session["BusinessUnitId"] = ulist[0].BusinessUnitId;
                            Session["BusinessUnitName"] = ulist[0].BusinessUnit.BusinessUnitName;
                            FormsService.SignIn(UserId.ToString(), model.RememberMe);
                            if (Url.IsLocalUrl(returnUrl))
                            {
                                return Redirect(returnUrl);
                            }
                            else
                            {
                                return RedirectToAction("Index", "Home");
                            }
                        }
                        else
                            ModelState.AddModelError("", "Not authorized in this Business Unit.");
                    }
                    else
                    {
                        ModelState.AddModelError("", "The user name or password provided is incorrect.");
                    }
                }
            }
            else
            {
                // Stage 3: OpenID Provider sending assertion response
                returnUrl = Session["ReturnUrl"].ToString();
                model = (LogOnModel)Session["LogonModel"];
                switch (response.Status)
                {
                    case AuthenticationStatus.Authenticated:
                        MembershipUser user = Membership.GetUser(response.ClaimedIdentifier, true);
                        if (user != null)
                        {
                            CoreEntities core = new CoreEntities();
                            Guid mId = new Guid(user.ProviderUserKey.ToString());
                            List<User> ulist = core.Users.Where(m => (m.ContactId == mId && m.IsDroppedYN == "N")).ToList();
                            bool fnd = true;
                            if (ulist.Count > 1) /* The user clearly has access to multiple BUs so redirect to select BU */
                            {
                                Guid ContactId = ulist[0].ContactId;
                                Session["ReturnUrl"] = returnUrl;
                                Session["RememberMe"] = model.RememberMe;
                                Session["UserContactId"] = ulist[0].ContactId;
                                return RedirectToAction("BusinessUnit", new { id = ContactId });
                            }
                            else if (ulist.Count < 1) /* The user obviously does not have access as there is no user record */
                            {
                                fnd = false;
                            }
                            else if (ulist.Count == 1) /* Allow user to select a BU for Sys Admins & Domain Admins by passing ContactId as Guid empty */
                            {
                                Guid UserId = ulist[0].UserId;
                                List<Authorization> auth = core.Roles.First(m => m.Name == "System Administrator").Authorizations.Where(u => u.UserId == UserId).ToList();
                                if (auth.Count > 0)
                                {
                                    Guid ContactId = Guid.Empty;
                                    Session["ReturnUrl"] = returnUrl;
                                    Session["RememberMe"] = model.RememberMe;
                                    Session["UserContactId"] = ulist[0].ContactId;
                                    return RedirectToAction("BusinessUnit", new { id = ContactId });
                                }
                                auth = core.Roles.First(m => m.Name == "Domain Administrator").Authorizations.Where(u => u.UserId == UserId).ToList();
                                if (auth.Count > 0)
                                {
                                    Guid ContactId = Guid.Empty;
                                    Session["ReturnUrl"] = returnUrl;
                                    Session["RememberMe"] = model.RememberMe;
                                    Session["UserContactId"] = ulist[0].ContactId;
                                    return RedirectToAction("BusinessUnit", new { id = ContactId });
                                }
                            }
                            if (fnd)
                            {
                                Guid UserId = ulist[0].UserId;
                                Guid ContactId = ulist[0].ContactId;
                                Contact C = core.Contacts.First(m => m.ContactId == ContactId);
                                Session["UserId"] = UserId;
                                Session["UserFullName"] = C.FullName;
                                Session["UserEmail"] = C.Email;
                                Session["BusinessUnitId"] = ulist[0].BusinessUnitId;
                                Session["BusinessUnitName"] = ulist[0].BusinessUnit.BusinessUnitName;
                                FormsService.SignIn(UserId.ToString(), model.RememberMe);
                                if (Url.IsLocalUrl(returnUrl))
                                {
                                    return Redirect(returnUrl);
                                }
                                else
                                {
                                    return RedirectToAction("Index", "Home");
                                }
                            }
                            else
                                ModelState.AddModelError("", "Not authorized in this Business Unit.");
                        }
                        else
                        {
                            ModelState.AddModelError("", "Account for that login was not found.");
                            return View(model);
                        }
                        return View(model);
                    case AuthenticationStatus.Canceled:
                        ModelState.AddModelError("", "Canceled at provider");
                        return View(model);
                    case AuthenticationStatus.Failed:
                        ModelState.AddModelError("", response.Exception.Message);
                        return View(model);
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }


        //
        // GET: /Account/BusinessUnit
        public ActionResult BusinessUnit(Guid id)
        {
            CoreEntities core = new CoreEntities();
            List<NameId> list = new List<NameId>();
            if(!id.Equals(Guid.Empty))
            {
                List<User> ulist = core.Users.Where(m => (m.ContactId == id && m.IsDroppedYN == "N")).ToList();
                foreach (User user in ulist)
                {
                    NameId n = new NameId();
                    n.Name = user.BusinessUnit.BusinessUnitName;
                    n.Id = user.BusinessUnitId.ToString();
                    list.Add(n);
                }
            }
            else
            {
                Guid DomainId = (Guid)Session["DomainId"];
                List<BusinessUnit> bulist = core.BusinessUnits.Where(m => (m.DomainId == DomainId && m.IsDroppedYN == "N")).ToList();
                foreach (BusinessUnit bu in bulist)
                {
                    NameId n = new NameId();
                    n.Name = bu.BusinessUnitName;
                    n.Id = bu.BusinessUnitId.ToString();
                    list.Add(n);
                }
            }
            if (list.Count > 1)
            {
                ViewBag.BUList = list;
                ViewBag.ContactId = (Guid)Session["UserContactId"];
                return View();
            }
            else
            {
                return BusinessUnitLogOn((Guid)Session["UserContactId"], new Guid(list[0].Id), core);
            }
        }

        //
        // POST: /Account/BusinessUnit

        [HttpPost]
        public ActionResult BusinessUnit(Guid ContactId, Guid selBusinessUnitId, FormCollection collection)
        {
            CoreEntities core = new CoreEntities();
            try
            {
                return BusinessUnitLogOn(ContactId, selBusinessUnitId, core);
            }
            catch (Exception e)
            {
                Tools.DebugInfo(Tools.ExceptionMessage(e));
            }
            return View();
        }

        private ActionResult BusinessUnitLogOn(Guid ContactId, Guid selBusinessUnitId, CoreEntities core)
        {
            List<Core.Models.User> users = core.Users.Where(m => (m.ContactId == ContactId && m.BusinessUnitId == selBusinessUnitId)).ToList();
            User user;
            if (users.Count > 0)
            {
                user = users[0];
            }
            else
            {
                user = core.Users.First(m => m.ContactId == ContactId);
            }
            BusinessUnit bu = core.BusinessUnits.First(m => m.BusinessUnitId == selBusinessUnitId);
            string returnUrl = Session["ReturnUrl"].ToString();
            bool RememberMe = (bool)Session["RememberMe"];
            Contact C = user.Contact;
            Session["UserId"] = user.UserId;
            Session["UserFullName"] = C.FullName;
            Session["UserEmail"] = C.Email;
            Session["BusinessUnitId"] = bu.BusinessUnitId;
            Session["BusinessUnitName"] = bu.BusinessUnitName;
            FormsService.SignIn(user.UserId.ToString(), RememberMe);
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }

        // **************************************
        // URL: /Account/LogOff
        // **************************************

        public ActionResult LogOff()
        {
            FormsService.SignOut();

            return RedirectToAction("Index", "Home");
        }

        // **************************************
        // URL: /Account/Register
        // **************************************

        public ActionResult Register()
        {
            // Some OpenID Authentication providers use GET instead of POST especially Google
            var response = openid.GetResponse();
            if (response != null)
            {
                RegisterModel model;
                ModelState.Clear();
                model = (RegisterModel)Session["RegisterModel"];
                Core.Tools.DebugInfo("User Registration: Need to process OpenID Auth response. RegistrationView = " + model.RegistrationView.ToString() + " & response.status = " + response.Status.ToString());
                Core.Tools.DebugInfo("User Registration: OpenId authentication response.Status = " + response.Status.ToString());
                switch (response.Status)
                {
                    case AuthenticationStatus.Authenticated:
                        // Complete the registration process
                        Core.Tools.DebugInfo("User Registration: OpenId authentication; completing registration process.");
                        string OpenIDUserName = response.ClaimedIdentifier;
                        string Email = model.Email;
                        string Comments = "";
                        var claim = response.GetExtension<ClaimsResponse>();
                        if (claim != null)
                        {
                            if (!String.IsNullOrEmpty(claim.Email)) Comments += "Email: " + claim.Email + " | ";
                            if (!String.IsNullOrEmpty(claim.FullName)) Comments += "FullName: " + claim.FullName + " | ";
                            if (!String.IsNullOrEmpty(claim.Nickname)) Comments += "Nickname: " + claim.Nickname + " | ";
                            if (!String.IsNullOrEmpty(claim.Country)) Comments += "Country: " + claim.Country + " | ";
                            if (!String.IsNullOrEmpty(claim.PostalCode)) Comments += "PostalCode: " + claim.PostalCode + " | ";
                            if (!String.IsNullOrEmpty(claim.TimeZone)) Comments += "TimeZone: " + claim.TimeZone + " | ";
                        }
                        // All conditions met, go ahead and activate the user.
                        ActivateUser(model, OpenIDUserName, Comments);
                        return RedirectToAction("ActivationSuccess");
                    case AuthenticationStatus.Canceled:
                        Core.Tools.DebugInfo("User Registration: OpenId authentication; cancelled at provider.");
                        ModelState.AddModelError("", "Canceled at provider");
                        return View(model);
                    case AuthenticationStatus.Failed:
                        Core.Tools.DebugInfo("User Registration: OpenId authentication; failed with error: " + response.Exception.Message);
                        ModelState.AddModelError("", response.Exception.Message);
                        return View(model);
                }
            }
            ModelState.Clear();
            ViewBag.PasswordLength = MembershipService.MinPasswordLength;
            RegisterModel m = new RegisterModel();
            m.RegistrationView = 1;
            m.BusinessUnitId = (Guid)Session["BusinessUnitId"];
            m.Password = "placeholder";
            m.ConfirmPassword = "placeholder";
            m.SecurityQuestion = "placeholder";
            m.SecurityAnswer = "placeholder";
            Core.Tools.DebugInfo("User Registration: Initiating Registration");
            return View(m);
        }

        [HttpPost]
        public ActionResult Register(RegisterModel model)
        {
            var response = openid.GetResponse();
            if (response != null)
            {
                ModelState.Clear();
                model = (RegisterModel)Session["RegisterModel"];
                Core.Tools.DebugInfo("User Registration: Retrieved Registration Model Info from Session");
            }
            if (ModelState.IsValid)
            {
                Core.Tools.DebugInfo("User Registration ModelState Validated. model.RegistrationView = " + model.RegistrationView.ToString());
                switch (model.RegistrationView)
                {
                    case 1:
                        // Make sure that the Security code is valid here
                        Core.Tools.DebugInfo("User Registration: Validating Security Code");
                        CoreEntities core = new CoreEntities();
                        List<ContactUser> cus = core.ContactUsers.Where(m => (m.Contact.Email == model.Email && m.InviteCode == model.InviteCode && m.InviteExpires > DateTime.Now)).ToList();
                        if (cus.Count() <= 0)
                        {
                            ModelState.AddModelError("", "Either the invitation has expired or there is no active invitation with that combination");
                            return View(model);
                        }
                        // Security code is valid so continue with registration.
                        if (model.UseOpenId)
                        {
                            Core.Tools.DebugInfo("User Registration: Valid Security Code, displaying OpenId Authentication view");
                            ViewBag.PasswordLength = MembershipService.MinPasswordLength;
                            RegisterModel m = new RegisterModel();
                            m.RegistrationView = 2;
                            m.BusinessUnitId = model.BusinessUnitId;
                            m.Email = model.Email;
                            m.InviteCode = model.InviteCode;
                            m.UseOpenId = model.UseOpenId;
                            m.Password = "placeholder";
                            m.ConfirmPassword = "placeholder";
                            m.SecurityQuestion = "placeholder";
                            m.SecurityAnswer = "placeholder";
                            ModelState.Clear();
                            return View(m);
                        }
                        else
                        {                            
                            ViewBag.PasswordLength = MembershipService.MinPasswordLength;
                            RegisterModel m = new RegisterModel();
                            m.RegistrationView = 3;
                            m.BusinessUnitId = model.BusinessUnitId;
                            m.Email = model.Email;
                            m.InviteCode = model.InviteCode;
                            m.UseOpenId = model.UseOpenId;
                            m.Password = "";
                            m.ConfirmPassword = "";
                            m.SecurityQuestion = "";
                            m.SecurityAnswer = "";
                            ModelState.Clear();
                            return View(m);
                        }
                    case 2:
                        if (response == null)
                        {
                            if (!String.IsNullOrEmpty(model.openid_identifier))
                            {
                                try
                                {
                                    var request = openid.CreateRequest(model.openid_identifier);
                                    request.AddExtension(new ClaimsRequest
                                    {
                                        FullName = DemandLevel.Require,
                                        Email = DemandLevel.Require,
                                        Nickname = DemandLevel.Require,
                                        Country = DemandLevel.Request,
                                        PostalCode = DemandLevel.Request,
                                        TimeZone = DemandLevel.Request
                                    });
                                    Session["RegisterModel"] = model;
                                    Core.Tools.DebugInfo("User Registration: OpenId authentication request created.");
                                    return request.RedirectingResponse.AsActionResult();
                                }
                                catch (ProtocolException ex)
                                {
                                    string msg = ex.Message.Contains("See the inner exception for details") ? ex.InnerException.Message : ex.Message;
                                    ModelState.AddModelError("", msg);
                                    Core.Tools.DebugInfo("User Registration: Error " + msg);
                                    return View(model);
                                }
                            }
                        }
                        else
                        {
                            // Stage 3: OpenID Provider sending assertion response
                            Core.Tools.DebugInfo("User Registration: OpenId authentication response.Status = " + response.Status.ToString());
                            switch (response.Status)
                            {
                                case AuthenticationStatus.Authenticated:
                                    // Complete the registration process
                                    Core.Tools.DebugInfo("User Registration: OpenId authentication; completing registration process.");
                                    string OpenIDUserName = response.ClaimedIdentifier;
                                    string Email = model.Email;
                                    string Comments = "";
                                    var claim = response.GetExtension<ClaimsResponse>();
                                    if (claim != null)
                                    {
                                        if (!String.IsNullOrEmpty(claim.Email)) Comments += "Email: " + claim.Email + " | ";
                                        if (!String.IsNullOrEmpty(claim.FullName)) Comments += "FullName: " + claim.FullName + " | ";
                                        if (!String.IsNullOrEmpty(claim.Nickname)) Comments += "Nickname: " + claim.Nickname + " | ";
                                        if (!String.IsNullOrEmpty(claim.Country)) Comments += "Country: " + claim.Country + " | ";
                                        if (!String.IsNullOrEmpty(claim.PostalCode)) Comments += "PostalCode: " + claim.PostalCode + " | ";
                                        if (!String.IsNullOrEmpty(claim.TimeZone)) Comments += "TimeZone: " + claim.TimeZone + " | ";
                                    }
                                    // All conditions met, go ahead and activate the user.
                                    ActivateUser(model, OpenIDUserName, Comments);
                                    return RedirectToAction("ActivationSuccess");
                                case AuthenticationStatus.Canceled:
                                    Core.Tools.DebugInfo("User Registration: OpenId authentication; cancelled at provider.");
                                    ModelState.AddModelError("", "Canceled at provider");
                                    return View(model);
                                case AuthenticationStatus.Failed:
                                    Core.Tools.DebugInfo("User Registration: OpenId authentication; failed with error: " + response.Exception.Message);
                                    ModelState.AddModelError("", response.Exception.Message);
                                    return View(model);
                            }
                        }
                        break;
                    case 3:
                        Core.Tools.DebugInfo("User Registration: Email/Password authentication; completing registration process.");
                        // All conditions met. Go ahead and activate the user
                        ActivateUser(model, model.Email, "");
                        return RedirectToAction("ActivationSuccess");
                }
            }

            // If we got this far, something failed, redisplay form
            Core.Tools.DebugInfo("User Registration: Major Failure.");
            ViewBag.PasswordLength = MembershipService.MinPasswordLength;
            model.RegistrationView = 1;
            return View(model);
        }

        private void ActivateUser(RegisterModel model, string OpenIDUserName, string Comments)
        {
            bool UseOpenId = (model.Email != OpenIDUserName);
            CoreEntities core = new CoreEntities();
            ContactUser cu = core.ContactUsers.First(m => m.Contact.Email == model.Email);
            cu.OpenIDUserName = OpenIDUserName;
            cu.Password = UseOpenId ? Tools.RandomString(64, false) : "";
            cu.SecurityQuestion = UseOpenId ? "This is an OpenID account. You should log in with your OpenID." : "";
            cu.SecurityAnswer = UseOpenId ? Tools.RandomString(64, false) : "";
            cu.Comment = Comments;
            cu.IsDroppedYN = "N";
            cu.IsApprovedYN = "Y";
            cu.IsLockedOutYN = "N";
            cu.LastActivityDT = DateTime.Now;
            cu.LastPasswordChangedDT = DateTime.Now;
            cu.Contact.Status = "A";
            cu.Contact.EmailVerifiedYN = "Y";
            core.SaveChanges();
            Contact c = cu.Contact;
            BusinessUnit bu = core.BusinessUnits.First(m => m.BusinessUnitId == model.BusinessUnitId);
            string emailbody = "Welcome! " +
                "You have been provided access for " + bu.BusinessUnitName + ".<br /><br />" +
                "You should be able to login at  http://" + Session["DomainName"].ToString() + " <br /><br />" +
                "Thank you.";
            string subject = "Account activated for " + bu.BusinessUnitName;
            List<EmailAddress> to = new List<EmailAddress>();
            to.Add(new EmailAddress((c.FirstName + (String.IsNullOrEmpty(c.LastName) ? "" : " " + c.LastName)), c.Email));
            Core.Tools.SendMail((Guid)Session["DomainId"], subject, emailbody, to);
            if (model.Email == OpenIDUserName)
            {
                MembershipCreateStatus status;
                Membership.CreateUser(OpenIDUserName, model.Password, model.Email, model.SecurityQuestion, model.SecurityAnswer, true, out status);
            }
        }

        public ActionResult ResetPasswordEmail()
        {
            return View();
        }

        [HttpPost]
        public ActionResult ResetPasswordEmail(ResetPasswordEmailModel model)
        {
            if (ModelState.IsValid)
            {
                MembershipUser u = Membership.GetUser(model.Email, false);
                if (u != null)
                {
                    TempData.Add("Email", model.Email);
                    return RedirectToAction("ResetPasswordAnswer", "Account");
                }
            }
            return View();
        }

        public ActionResult ResetPasswordAnswer()
        {                        
            MembershipUser u = null;
            try
            {
                u = Membership.GetUser(TempData["Email"].ToString(), false);
            }
            catch (Exception e)
            {
                ModelState.AddModelError("", Tools.ExceptionMessage(e));
            }
            
            if (u != null)
            {
                ResetPasswordAnswerModel model = new ResetPasswordAnswerModel();
                model.Email = u.Email;
                model.Question = u.PasswordQuestion;
                return View(model);
            }
            return RedirectToAction("ResetPasswordEmail");
        }

        [HttpPost]
        public ActionResult ResetPasswordAnswer(ResetPasswordAnswerModel model)
        {
            if (ModelState.IsValid)
            {
                MembershipUser u = Membership.GetUser(model.Email);
                try
                {
                    string genPassword = u.ResetPassword(model.SecurityAnswer);
                    bool IsSuccess = u.ChangePassword(genPassword, model.Password);
                    if (IsSuccess) return RedirectToAction("ResetPasswordSuccess");
                }
                catch (MembershipPasswordException e)
                {
                    ModelState.AddModelError("", e.Message);
                }
            }
            return View(model);
        }

        public ActionResult ResetPasswordSuccess()
        {
            return View();
        }

        public ActionResult NoPermission()
        {
            return View();
        }

        public ActionResult ActivationSuccess()
        {
            return View();
        }

        // **************************************
        // URL: /Account/ChangePassword
        // **************************************

        [Authorize]
        public ActionResult ChangePassword()
        {
            ViewBag.PasswordLength = MembershipService.MinPasswordLength;
            return View();
        }

        [Authorize]
        [HttpPost]
        public ActionResult ChangePassword(ChangePasswordModel model)
        {
            if (ModelState.IsValid)
            {
                CoreEntities core = new CoreEntities();
                Guid UserId = new Guid(User.Identity.Name);
                string useremail = core.Users.First(m => m.UserId == UserId).Contact.Email;
                if (MembershipService.ChangePassword(useremail, model.OldPassword, model.NewPassword))
                {
                    return RedirectToAction("ChangePasswordSuccess");
                }
                else
                {
                    ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
                }
            }

            // If we got this far, something failed, redisplay form
            ViewBag.PasswordLength = MembershipService.MinPasswordLength;
            return View(model);
        }

        // **************************************
        // URL: /Account/ChangePasswordSuccess
        // **************************************

        [Authorize]
        public ActionResult ChangePasswordSuccess()
        {
            return View();
        }

        //
        // GET: /Account/Profile

        [Authorize]
        public ActionResult Profile()
        {
            CoreEntities core = new CoreEntities();
            Guid UserId = new Guid(User.Identity.Name);
            User user = core.Users.First(m => m.UserId == UserId);
            return View(user);
        }

        //
        // GET: /Account/ChangeQuestionAnswer

        [Authorize]
        public ActionResult ChangeQuestionAnswer()
        {
            CoreEntities core = new CoreEntities();
            Guid UserId = new Guid(User.Identity.Name);
            User user = core.Users.First(m => m.UserId == UserId);
            ChangeQuestionAnswerModel cqa = new ChangeQuestionAnswerModel();
            cqa.Question = user.Contact.ContactUsers.First(m => m.ContactId == user.ContactId).SecurityQuestion;
            return View(cqa);
        }

        //
        // POST: /Account/ChangeQuestionAnswer
        [HttpPost]
        [Authorize]
        public ActionResult ChangeQuestionAnswer(ChangeQuestionAnswerModel cqa)
        {
            CoreEntities core = new CoreEntities();
            Guid UserId = new Guid(User.Identity.Name);
            string useremail = core.Users.First(m => m.UserId == UserId).Contact.Email;
            MembershipUser user = Membership.GetUser(useremail, true);
            bool success = user.ChangePasswordQuestionAndAnswer(cqa.Password, cqa.SecurityQuestion, cqa.SecurityAnswer);
            if (success)
            {
                return RedirectToAction("ChangeQuestionAnswerSuccess");
            }
            else
            {
                ModelState.AddModelError("", "The current password is incorrect or there was some other error.");
            }
            return View(cqa);
        }

        //
        // GET: /Account/ChangeQuestionAnswerSuccess

        [Authorize]
        public ActionResult ChangeQuestionAnswerSuccess()
        {
            return View();
        }

    }
}
